///////////////////////////////////////////////////////////////////////////////
////  (c) Chaichuk AU (chaichuk@mail.ru), 								   ////
////  2005, Chelyabinsk, NTC Privodnaya Tehnika (momentum@chel.surnet.ru)  ////
///////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

struct   abs_dpm_attr_s;
#define  IOFUNC_ATTR_T struct abs_dpm_attr_s

#include <sys/iofunc.h>
#include <sys/dispatch.h>
#include <time.h>
#include <sys/netmgr.h>
#include <hw/inout.h>

#include "iofuncs.h"
#include "anybus_pci.h"
#include "color.h"

static	void	optproc (int, char **);
static	void	execute_resmgr (void);

const char*		progname = "hms-dpm";
const char* 	name0 	 = "/dev/hms-dpm0";
const char* 	name1 	 = "/dev/hms-dpm1";


abs_dpm_attr_t	attr0,
                attr1;
int				just_reboot_it = 0;

int				intr_cntr = 0;
int				intr_cntr_2 = 0;

#define TRUE  1
#define FALSE 0

//#define DEBUG_DPMASTER_C

char* get_time_now ()
{
	time_t tod;
	static char out [100];
	
	time (&tod);
    strftime (out, sizeof (out), "%d-%m-%Y %T", localtime (&tod));	
    
    return out;
}

/****************************************************************************
 * FUNCTION NAME: sig_handler
 *
 * DESCRIPTION  : 
 *
 * RETURN VALUE : 
 ***************************************************************************/
void sig_handler (int sig)
{
//	arc20_exit (&attr.arc20);
}

/****************************************************************************
 * FUNCTION NAME: intr_handler
 *
 * DESCRIPTION  : 
 *
 * RETURN VALUE : 
 ***************************************************************************/
const struct sigevent * intr_handler (void *area, int id)
{
	abs_pci_board_t	*board = (abs_pci_board_t *) area;
	abs_module_t *abs = &board->abs_module;
		
	intr_cntr ++;
	out16 (board->iobase + PLX_INTR_REG, LINT2_ACK);
	if ((*abs->indic_register_rw_ptr)& ABS_AP_EVNT != 
		(*abs->indic_register_ro_ptr)& ABS_AB_EVNT) {
	
		intr_cntr_2 ++;
//		*abs->indic_register_rw_ptr ^= ABS_AP_EVNT;		
		if ((*abs->indic_register_rw_ptr) & ABS_AP_EVNT) {
			*abs->indic_register_rw_ptr &= ~ABS_AP_EVNT;
		}
		else {
			*abs->indic_register_rw_ptr |= ABS_AP_EVNT;
		}
	}

	return NULL;
}

/****************************************************************************
 * FUNCTION NAME: io_thread
 *
 * DESCRIPTION  : 
 *
 * RETURN VALUE : 
 ***************************************************************************/
void* io_thread (void *arg)
{
	abs_pci_board_t	*board = (abs_pci_board_t *) arg;
	abs_module_t *abs = &board->abs_module;
//	int intr_id;
//	int mask;
	
//	printf ("intr_cntr = %d\n", intr_cntr);
	
//	mask = PCI_INTR_ENABLE | LINT2_ENABLE;/* | LINT1_HIGH /*| LINT1_EDGE;//|LINT2_ENABLE|LINT2_HIGH|LINT2_EDGE;*/
//	out16 (board->iobase + PLX_INTR_REG, mask);
		
//	intr_id = InterruptAttach (board->irq, intr_handler, board, sizeof (abs_pci_board_t), 0);
//	InterruptUnmask (board->irq, intr_id);
	
	
#define MAX_TRY	100
	
	while (1) {
//		printf ("%sabs_request_output_data_area (abs);%s\n", GREEN, SGR0);
		abs_request_output_data_area (abs);
		do {
			abs_update_status (abs);
		} while (!abs->out_area_free);
		
		memcpy (abs->input_buf, abs->output_data_area_ptr, abs->init_input_len);

//		printf ("%sabs_release_output_data_area (abs);%s\n", GREEN, SGR0);
		abs_release_output_data_area (abs);
		do {
			abs_update_status (abs);
		} while (abs->out_area_free);

//		printf ("%sabs_request_input_data_area (abs);%s\n", GREEN, SGR0);	
		abs_request_input_data_area (abs);
		do {
			abs_update_status (abs);
		} while (!abs->in_area_free);
	
		memcpy (abs->input_data_area_ptr, abs->output_buf, abs->init_output_len);

//		printf ("%sabs_release_input_data_area (abs);%s\n", GREEN, SGR0);
		abs_release_input_data_area (abs);
		do {
			abs_update_status (abs);
		} while (abs->in_area_free);
		
		delay (1);

	}
	
//	InterruptDetach (intr_id);
}

/****************************************************************************
 * FUNCTION NAME: main
 *
 * DESCRIPTION  :
 *
 * RETURN VALUE :
 ***************************************************************************/
int main (int argc, char **argv)
{
	struct sched_param param;

	if (ThreadCtl (_NTO_TCTL_IO, 0) == -1) {
		fprintf (stderr, "%s:  can't obtain I/O privilege; ensure you are running as root! (errno %d (%s))\n", progname, errno, strerror (errno));
		exit (EXIT_FAILURE);
	}

	optproc (argc, argv);

	param.sched_priority = 40;
	sched_setparam (0, &param);

	execute_resmgr ();						// never returns

	return (EXIT_SUCCESS);
}

/****************************************************************************
 * FUNCTION NAME: execute_resmgr
 *
 * DESCRIPTION  : 
 *
 * RETURN VALUE : 
 ***************************************************************************/
static void execute_resmgr (void)
{
	resmgr_attr_t			resmgr_attr;
	resmgr_connect_funcs_t	connect_func;
	resmgr_io_funcs_t		io_func0,
	                        io_func1;
	dispatch_t				*dpp;
	resmgr_context_t		*ctp;


	// create the dispatch structure
	if ((dpp = dispatch_create ()) == NULL) {
		perror ("Unable to dispatch_create().");
		exit (EXIT_FAILURE);
	}

	// initialize the various data structures
	memset (&resmgr_attr, 0, sizeof (resmgr_attr_t));

	// bind default functions into the outcall tables
	iofunc_func_init (_RESMGR_CONNECT_NFUNCS, &connect_func, _RESMGR_IO_NFUNCS, &io_func0);
	iofunc_attr_init (&attr0.attr, S_IFNAM | 0666, 0, 0);
	iofunc_func_init (_RESMGR_CONNECT_NFUNCS, &connect_func, _RESMGR_IO_NFUNCS, &io_func1);
	iofunc_attr_init (&attr0.attr, S_IFNAM | 0666, 0, 0);
		
	if (abs_pci_init_board (&attr0.board, 0) == -1) {
		fprintf (stderr, "error abs_pci_init_board\n");
		exit (EXIT_FAILURE);
	}

	if (just_reboot_it) {
		fprintf (stdout, "%s", GREEN);
		fprintf (stdout, "reseting anybus module .. 1 second, pls ..");
		fprintf (stdout, "%s\n", SGR0);
		abs_sw_reset (&attr0.board.abs_module);
		delay (2000);
		exit (EXIT_FAILURE);
	}

	if (pthread_create (NULL, NULL, io_thread, &attr0.board) != EOK)
		exit (EXIT_FAILURE);

	signal (SIGTERM, sig_handler);
//	signal (SIGKILL, sig_handler);
//	signal (SIGQUIT, sig_handler);
//	signal (SIGINT,  sig_handler);
//	signal (SIGABRT, sig_handler);
//	signal (SIGTSTP, sig_handler);
//	signal (SIGSTOP, sig_handler);
		
	io_func0.devctl 	= io_devctl;
	// establish a name in the pathname space
	if (resmgr_attach (dpp, &resmgr_attr, name0, _FTYPE_ANY, 0, &connect_func, &io_func0, &attr0) == -1) 
	{
		perror ("Unable to resmgr_attach. ");
		exit (EXIT_FAILURE);
	}
	
    io_func1.devctl 	= io_devctl;
	// establish a name in the pathname space
	if (resmgr_attach (dpp, &resmgr_attr, name1, _FTYPE_ANY, 0, &connect_func, &io_func1, &attr0) == -1) 
	{
		perror ("Unable to resmgr_attach. ");
		exit (EXIT_FAILURE);
	}


	ctp = resmgr_context_alloc (dpp);
	
	// wait here forever, handling messages
	while (1) {
		if ((ctp = resmgr_block (ctp)) == NULL) {
			perror ("Unable to resmgr_block(). ");
			exit (EXIT_FAILURE);
		}
		resmgr_handler (ctp);
	}
}

/****************************************************************************
 * FUNCTION NAME: usageError
 *
 * DESCRIPTION  :
 *
 * RETURN VALUE :
 ***************************************************************************/
static void usageError (void)
{
	fprintf (stderr, "%s:  error in use, type \"use %s\" for usage\n", progname, progname);
//	exit (1);
}

/****************************************************************************
 * FUNCTION NAME: optproc
 *
 * DESCRIPTION  :
 *
 * RETURN VALUE :
 ***************************************************************************/
static void optproc (int argc, char **argv)
{
	int opt;

	while ((opt = getopt (argc, argv, "r")) != -1) {
		switch (opt) {

		case 'r':
			just_reboot_it = 1;
			break;

		default:
			usageError ();
			break;
		}
	}
}